#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
此模块实现了数据导入功能，负责读取Excel文件、验证数据并加载数据。
提供了 DataImporter 类来处理Excel文件的导入和数据验证工作。

该模块会对输入的Excel文件进行存在性检查，支持读取第一个工作表，
可处理历史数据和普通数据，对数据格式、必需字段、数值和日期等进行验证，
最后将验证后的数据转换为指定类型并重置索引后返回。
"""

import os
import logging

import pandas as pd

from src.config.constants import HISTORICAL_FIELDS, REQUIRED_FIELDS
from src.config.exceptions import DataValidationError
from src.utils.excel_utils import ExcelUtils

# 配置日志
logger = logging.getLogger("data_import")


class DataImporter:
    """负责Excel文件读取、数据验证和加载"""

    def __init__(self):
        """初始化数据导入器"""
        self.excel_utils = ExcelUtils()

    def import_excel_file(self, file_path, is_historical=False):
        """导入Excel文件数据

        Args:
            file_path: Excel文件路径
            is_historical: 是否为历史数据文件

        Returns:
            导入的DataFrame数据

        Raises:
            FileNotFoundError: 文件不存在
            DataValidationError: 数据验证失败
        """
        # 检查文件是否存在
        if not os.path.exists(file_path):
            raise FileNotFoundError(f"文件不存在: {file_path}")

        # 读取Excel文件
        try:
            # 指定读取第一个工作表，并确保规格型号列为字符串类型
            dtype = {"规格型号": str}
            data = self.excel_utils.read_excel(
                file_path, sheet_name=0, dtype=dtype
            )
            # 验证数据
            validated_data = self.validate_data(data, is_historical)
            # 加载数据
            loaded_data = self.load_data(validated_data)
            return loaded_data
        except Exception as e:
            if isinstance(e, DataValidationError):
                raise
            raise DataValidationError(f"导入文件失败: {str(e)}") from e

    def validate_data(self, data, is_historical=False):
        """验证导入的数据

        Args:
            data: 待验证的数据（DataFrame）
            is_historical: 是否为历史数据

        Returns:
            验证通过的数据

        Raises:
            DataValidationError: 数据验证失败
        """
        # 检查数据类型
        if not isinstance(data, pd.DataFrame):
            raise DataValidationError("导入的数据不是有效的DataFrame格式")

        # 检查数据是否为空
        if data.empty:
            raise DataValidationError("导入的文件为空")

        # 根据数据类型检查必需字段
        required_fields = (
            HISTORICAL_FIELDS if is_historical else REQUIRED_FIELDS
        )

        # 检查必需字段是否存在
        missing_fields = [
            field for field in required_fields if field not in data.columns
        ]
        if missing_fields:
            raise DataValidationError(
                f"缺少必需的字段: {', '.join(missing_fields)}"
            )

        # 检查关键字段是否有值
        for field in required_fields:
            if data[field].isnull().all():
                raise DataValidationError(f"字段 '{field}' 全部为空")

        # 检查数值字段的格式
        numeric_fields = ["数量"]
        for field in numeric_fields:
            if field in data.columns:
                try:
                    data[field] = pd.to_numeric(data[field], errors="raise")
                except ValueError as exc:
                    raise DataValidationError(
                        f"字段 '{field}' 包含非数值数据"
                    ) from exc

        # 检查日期字段的格式
        date_fields = ["预完工日期"]
        for field in date_fields:
            if field in data.columns:
                try:
                    # 使用coerce模式转换日期，无效日期会被转换为NaT
                    data[field] = pd.to_datetime(data[field], errors="coerce")

                    # 获取无法解析的日期数量
                    invalid_date_count = data[field].isnull().sum()
                    total_count = len(data[field])

                    # 如果存在无法解析的日期，记录警告但允许继续处理
                    if invalid_date_count > 0:
                        logger.warning(
                            f"字段 '{field}' 中有 {invalid_date_count}/{total_count} 个无效的日期格式，将被设置为NaT"
                        )

                except Exception as exc:
                    # 如果完全无法解析，记录错误并跳过此字段的验证
                    logger.error(
                        f"解析字段 '{field}' 的日期时发生错误: {str(exc)}"
                    )
                    # 不抛出异常，允许继续处理

        return data

    def load_data(self, validated_data):
        """加载验证后的数据

        Args:
            validated_data: 验证后的数据

        Returns:
            加载后的数据
        """
        # 确保规格型号字段为字符串类型
        if "规格型号" in validated_data.columns:
            validated_data["规格型号"] = validated_data["规格型号"].astype(str)

        # 确保数量字段为整数类型，使用可空整数类型处理NA值
        if "数量" in validated_data.columns:
            # 先检查是否有NA值
            if validated_data["数量"].isnull().any():
                # 如果有NA值，使用可空整数类型Int64
                validated_data["数量"] = validated_data["数量"].astype("Int64")
                logger.warning("数量字段中包含NA值，使用可空整数类型Int64处理")
            else:
                # 如果没有NA值，使用普通整数类型
                validated_data["数量"] = validated_data["数量"].astype(int)

        # 重置索引
        loaded_data = validated_data.reset_index(drop=True)

        return loaded_data

    def import_task_data(self, file_path):
        """导入任务数据

        Args:
            file_path: 任务数据文件路径

        Returns:
            导入的任务数据
        """
        return self.import_excel_file(file_path, is_historical=False)

    def import_historical_data(self, file_path):
        """导入历史数据

        Args:
            file_path: 历史数据文件路径

        Returns:
            导入的历史数据
        """
        return self.import_excel_file(file_path, is_historical=True)
